﻿// <copyright file="XsltExtensions.cs" company="Auros Ltd.">
//     Copyright (c) Auros Ltd. All rights reserved.
// </copyright>

namespace Auros.Categorisation
{
    using System;
    using System.Collections.Generic;
    using System.Xml.Linq;
    using System.Xml.XPath;
    using Auros.Categorisation.Data;
    using umbraco;

    /// <summary>
    /// Class containing methods for working with category data within XSLT.
    /// </summary>
    [XsltExtension("Auros.Categories")]
    public class XsltExtensions
    {
        /// <summary>
        /// Gets the name of the category.
        /// </summary>
        /// <param name="categoryId">The category id to return the name of.</param>
        /// <returns>The name of the category.</returns>
        public static string GetCategoryName(ushort categoryId)
        {
            Category category = new CategoryRepository().GetCategory(categoryId);

            // Return the name of the category.
            if (category != null)
                return category.Name;
            else
                return null;
        }

        /// <summary>
        /// Gets a single category.
        /// </summary>
        /// <param name="categoryId">The category id.</param>
        /// <returns>XPath navigable details for a single category.</returns>
        public static XPathNavigator GetCategory(ushort categoryId)
        {
            Category category = new CategoryRepository().GetCategory(categoryId);

            if (category == null)
                return null;
            else
            {
                XDocument document = new XDocument(CreateCategoryXmlElement(category));

                // Return navigator object.
                return document.CreateNavigator();
            }
        }

        /// <summary>
        /// Gets all enabled categories.
        /// </summary>
        /// <returns>XPath navigable collection of category items.</returns>
        public static XPathNavigator GetCategories()
        {
            IEnumerable<Category> categories = new CategoryRepository().GetCategories();

            XDocument document = CreateCategoriesXDocument(categories);

            // Return navigator object.
            return document.CreateNavigator();
        }

        /// <summary>
        /// Gets all categories.
        /// </summary>
        /// <returns>XPath navigable collection of category items.</returns>
        public static XPathNavigator GetAllCategories()
        {
            IEnumerable<Category> categories = new CategoryRepository().GetCategories();

            XDocument document = CreateCategoriesXDocument(categories);

            // Return navigator object.
            return document.CreateNavigator();
        }

        /// <summary>
        /// Gets all child categories categories of the specified parent.
        /// </summary>
        /// <param name="parentId">The parent category id.</param>
        /// <returns>XPath navigable collection of category items.</returns>
        public static XPathNavigator GetChildCategories(ushort parentId)
        {
            IEnumerable<Category> categories = new CategoryRepository().GetCategories(parentId);

            XDocument document = CreateCategoriesXDocument(categories);

            // Return navigator object.
            return document.CreateNavigator();
        }

        /// <summary>
        /// Gets all child categories categories of the specified parent.
        /// </summary>
        /// <param name="parentId">The parent category id.</param>
        /// <returns>XPath navigable collection of category items.</returns>
        public static XPathNavigator GetAllChildCategories(ushort parentId)
        {
            IEnumerable<Category> categories = new CategoryRepository().GetCategories(parentId);

            XDocument document = CreateCategoriesXDocument(categories);

            // Return navigator object.
            return document.CreateNavigator();
        }

        /// <summary>
        /// Gets the categories from CSV.
        /// </summary>
        /// <param name="csvString">The CSV string.</param>
        /// <returns>XPath navigable collection of category items.</returns>
        public static XPathNavigator GetCategoriesFromCSV(string csvString)
        {
            var ids = StringHelpers.StringToIntList(csvString);

            var categories = GetCategoriesFromIntegers(ids);

            XDocument document = CreateCategoriesXDocument(categories);

            // Return navigator object.
            return document.CreateNavigator();
        }

        #region Private Extension Helpers

        /// <summary>
        /// Gets the categories from integer IDs.
        /// </summary>
        /// <param name="categoryIds">The category ids.</param>
        /// <returns>Enumerable collection of categories.</returns>
        private static IEnumerable<Category> GetCategoriesFromIntegers(IEnumerable<int> categoryIds)
        {
            foreach (var id in categoryIds)
            {
                var category = new CategoryRepository().GetCategory(id);

                if (category != null)
                    yield return category;
            }
        }

        /// <summary>
        /// Creates a categories XDocument object.
        /// </summary>
        /// <param name="categories">The categories to add to the document.</param>
        /// <returns>XDocument object containing category items.</returns>
        private static XDocument CreateCategoriesXDocument(IEnumerable<Category> categories)
        {
            if (categories == null)
                throw new ArgumentNullException("categories");

            XDocument document = new XDocument(
                new XElement(
                    "categories",
                    CreateCategoryXmlElements(categories)));

            return document;
        }

        /// <summary>
        /// Creates the category XML elements.
        /// </summary>
        /// <param name="categories">Enumerable collection of category items.</param>
        /// <returns>Enumerable object of XElement items.</returns>
        private static IEnumerable<XElement> CreateCategoryXmlElements(IEnumerable<Category> categories)
        {
            if (categories == null)
                throw new ArgumentNullException("categories");

            foreach (var item in categories)
                yield return CreateCategoryXmlElement(item);
        }

        /// <summary>
        /// Creates the category XML element.
        /// </summary>
        /// <param name="category">Category item.</param>
        /// <returns>XElement object for the specified category.</returns>
        private static XElement CreateCategoryXmlElement(Category category)
        {
            if (category == null)
                throw new ArgumentNullException("category");

            return new XElement(
                "category",
                new XAttribute("id", category.ID),
                new XAttribute("parent", category.Parent == null ? 0 : category.Parent.ID),
                new XAttribute("enabled", category.Enabled),
                new XAttribute("selectable", category.Selectable),
                new XElement("name", category.LocalizedName),
                new XElement("description", category.LocalizedDescription));
        }

        #endregion
    }
}